#ifndef _BAM_OBJECTIVE_SOCKET_ROUTER_
#define _BAM_OBJECTIVE_SOCKET_ROUTER_

#include "../common/packet.h"
#include "../osocklib/osocklib.h"
#include "../osocklib/sockstack.h"
#include "../sspsock/sspsock.h"

#include <iostream>

//#include "C:\\Documents and Settings\\sfaktorovich\\My Documents\\remoteconsole2\\vld.h"

namespace BAM
{

	using namespace std;

	class cRoutersHolder;

	class iRouter:public iSelectable
	{
	public:

		virtual ~iRouter() {}

		virtual void start() = 0;

		virtual void onReadable(cRoutersHolder &Owner) = 0;
		virtual void onIdle(cRoutersHolder &Owner) = 0;

		virtual bool isActive() = 0;
		virtual bool isDead() = 0;

		virtual dword getAllParty(iRouter **Dest, dword MaxCount)=0;

	};

	const timeval ROUTER_IdleTime = {0, 500}; 

	class cRoutersHolder
	{
		cTSelector<iRouter, iRouter> vSelector;
	public:

		void add(iRouter *R)
		{
			if(!vSelector.getSet().isset(R))
				vSelector.getSet().set(R, true);
		}
		void del(iRouter *R)
		{
			vSelector.getSet().clr(R);
		}

		dword count(){return vSelector.getSet().count();}
		//    const iRouter& operator[](dword Index)const{return vSelector.getSet()[Index];}
		iRouter* operator[](dword Index)
		{return vSelector.getSet()[Index];}

		void run();
	};

	class iRouterControler
	{
	public:
		virtual bool onRecv(cPacket &P, iConnection &Con) =0;
		virtual bool onSend(cPacket &P, iConnection &Con) =0;
		virtual bool onRouteBeforeInit(cIPAddr &Dest, iConnection &Src) = 0;
		virtual bool onRouteInit(iConnection &Dest, iConnection &Src) = 0;
		virtual void onError(const char* Err) = 0;
		virtual void onDisconnect(iConnection &Con)=0;
	};

	class iCRouter:public iRouter
	{
	public:
		virtual void setControler(iRouterControler *Control, bool Own = false) =0;
	};

	class cTrafficLog:public iRouterControler
	{
		ostream *vFile;
		bool vOwn;
		bool vFull;
#ifndef _WIN32
		dword vCnt;
#endif
	public:
		cTrafficLog(const char *FileName, bool Full);
		cTrafficLog(ostream *Os, bool Full, bool Own);
		~cTrafficLog();
		bool onRecv(cPacket &P, iConnection &Con);
		bool onSend(cPacket &P, iConnection &Con);
		bool onRouteBeforeInit(cIPAddr &Dest, iConnection &Src);
		bool onRouteInit(iConnection &Dest, iConnection &Src);
		void onError(const char* Err);
		void onDisconnect(iConnection &Con);
	};

	class cForwarderPort:public iCRouter
	{
	private:
		iSocket *vSock;
		iRouterControler *vControl;
		cForwarderPort *vPair;
		std::queue<cPacket> vQueue;

	protected:
		class cForwarderPortJob: public iRunnable
		{
		private:
			cForwarderPort* m_ForwarderPort;
			cRoutersHolder& m_RoutersHolder; 
		public:
			cForwarderPortJob(cForwarderPort *forwarderPort, cRoutersHolder &owner);
			void run();
			void stop();
			~cForwarderPortJob() { }
		};

		cThread* m_Thread;
		cForwarderPortJob* m_Job;




	public:

		cForwarderPort(iSocket *Sock, cRoutersHolder &owner);
		~cForwarderPort();

		void setPair(cForwarderPort *Pair);
		void send(const cPacket &P)
		{
			cPacket Tmp = P;
			try
			{
				if(!vControl || vControl->onSend(Tmp, *vSock)) vSock->send(Tmp);
			}
			catch (...)
			 {/* !!! */	}
				
		}
		iSocket* getSocket(){return vSock;}

		void setControler(iRouterControler *Control, bool Own = false);

		void start();

		void onReadable(cRoutersHolder &Owner);
		void onIdle(cRoutersHolder &Owner);

		bool isActive(){return (vQueue.size() > 0);}

		bool isSDead()
		{
			bool ret; 
			try
			{
				ret =  (!vSock || ((vSock->state() != SSTATE_CONNECTED) && (vSock->state() != SSTATE_CONNECTING)));
			}
			catch (...)
			{
				ret = true;
			}
			return ret;
		}

		bool isDead()
		{
			bool ret;
			try
			{
				ret = (!vPair || vPair->isSDead() || !vSock || ((vSock->state() != SSTATE_CONNECTED) && (vSock->state()!=SSTATE_CONNECTING)));
			}
			catch(...)
			{
				ret = true;
			}
			return ret;
		}

		dword getAllParty(iRouter **Dest, dword MaxCount);

		bool isReadable(){return vSock && (vSock->isReadable());}
		bool isWriteable(){return vSock && vSock->isWriteable();}/* *** */
		bool isAcceptable(){return vSock && vSock->isAcceptable();}
		SOCKET descriptor() {return vSock && vSock->descriptor();}
	};

	class cForwarder:public iCRouter
	{
		cServerSocket *vSock;
		iRouterControler *vControl;
		bool vOwnControl;
		iRouterControler *vChildControl;
		cIPAddr vLAddr, vDAddr;
		cLoginManager *vLm;
		char * vDLogin;
		bool vOwnLm, vSecInc;
	public:

		cForwarder(const cIPAddr DAddr, const cIPAddr &LAddr);
		~cForwarder();

		void setSecure(cLoginManager *lm, bool SecInc, const char *DLogin, bool ownLm);
		void setControler(iRouterControler *Control, bool Own = false);
		void setChildControler(iRouterControler *Control);

		void start();

		void onReadable(cRoutersHolder &Owner);
		void onIdle(cRoutersHolder &Owner);

		bool isActive(){return false;}
		bool isDead(){return (!vSock || (vSock->state() != SSTATE_LISTENING));}

		dword getAllParty(iRouter **Dest, dword MaxCount);
		bool isReadable(){return vSock->isReadable();}
		bool isWriteable(){return vSock->isWriteable();}
		bool isAcceptable(){return vSock->isAcceptable();}
		SOCKET descriptor(){return vSock->descriptor();}
	};

}

#endif
